﻿
// 类和对象 <<下>> 的相关练习


/////////////////////////////  又一重要问题

//构造函数
// 初始化列表
// 构造函数的作用是进行初始化的 , 根据之前所学, 默认构造对内置类型没有处理 ,对自定义类型必须调用它的默认构造 , 若没有就会报错
// 那么当自定义类型没有默认构造还想进行初始化时,就必须用初始化列表进行初始化

//特点:
// 1. 以冒号开始 , 逗号分隔 , 要在函数体的外面,每个成员变量后跟一个括号,括号内容是初始化的内容
// 2. 初始化列表是对类的成员变量进行初始化 ,并且只能出现一次  - > 原因是: 初始化列表是成员变量定义的地方
//  然而,在类中我们有成员变量声明的地方 , 这样就全了 , 一个变量声明了以后都会找定义 , 定义只能定义一次 , 所以:每个成员变量都会走初始化列表
// 3. 对于 引用成员变量 , const 修饰的成员变量 , 自定义类型没有默认构造的 , 这三者必须走初始化列表
//   因为: 引用必须初始化,而初始化列表是其定义的地方,所以可以完成初始化
//        const 修饰的成员变量在定义一个值以后就不能在被改变了 , 所以要走定义就是初始化列表
//        自定义类型没有默认构造的 , 要走初始化列表初始化
// 4. ***** 注意: 初始化列表的初始化顺序是与声明时的顺序有关的 , 先声明的先初始化 , 与定义无关

// 5. C++ 11 支持在声明的时候给缺省值(默认值) , 声明处给缺省值是给初始化列表使用的
//    若初始化列表中显示没有对某个变量初始化, 那么这个对应的缺省值就会给其初始化

/////// 总结: 尽量使用初始化列表初始化, 因为初始化列表是成员变量定义的地方,即使不使用初始化列表也会走初始化列表
///////      初始化列表有以下情况:
//////       1. 声明处给了缺省值 
//////          a. 显示初始化了就用显示的
//////          b. 未显示初始化的就用缺省值初始化
//           2. 声明处没有缺省值 
//				a. 对于内置类型没有规定 , 随机值
//				b. 对于自定类型要初始化只能走默认构造 , 若没有默认构造就会报错	
//////


//初始化列表初始化

//函数部分给了缺省值是为了应对函数传参时没有给参数的情况
//Date::Date(int year , int month , int day)
//	:_year(year)
//	,_month(month)
//	,_day(day)
//{}





#include <iostream>

using namespace std;


//定义一个日期类


//class Time
//{
//public:
//
//	//Time(int hour = 1 , int minute = 1);
//	//给一个无参的默认构造
//	Time()
//		:_hour(10)
//	{
//		cout << "Time()" << endl;
//	}
//
//
//
//
//private:
//	int _hour;
//};
//
//class Date
//{
//
//public:
//
//	//构造 - > 初始化列表
//
//	//函数部分给了缺省值是为了应对函数传参时没有给参数的情况
//    //而成员声明部分给缺省值是为了应对以下情况
//	Date(int year = 1990, int month = 1, int day = 2)
//		:_year(year)
//		, _month(month)
//		//这里没有对 _day 进行初始化就会用声明处的缺省值进行初始化 , 与函数给缺省值无关了 
//	{}
//
//	void Print()
//	{
//		cout << _year << "年" << _month << "月" << _day << "日" << endl;
//	}
//
//private:
//	//这里是声明 
//	//若给了缺省值 , 这里的缺省值是给 初始化列表中初始化使用的
//	int _year = 1;
//	int _month = 1;
//	//int _day = 1;
//	//若没有给缺省值,初始化列表也没有显示,就是随机值
//	int _day = 1;
//
//	//给了自定义类型 ,若未显示初始化就会调用它的默认构造 ,这里调用 Time()
//	Time time = 1;
//
//};

//
//class Time
//{
//public:
//	Time(int hour)
//		:_hour(hour)
//	{
//		cout << "Time()" << endl;
//	}
//private:
//	int _hour;
//};
//
//class Date
//{
//public:
//	Date(int year = 1, int month = 1, int day = 1)
//		:_year(year)
//		,_month(month)
//	{}
//
//	void Print() const
//	{
//		cout << _year << "-" << _month << "-" << _day << endl;
//	}
//
//private:
//	// C++11
//	// 声明，缺省值->初始化列表用的
//	int _year = 1;
//	int _month = 1;
//	int _day;
//
//	//会走缺省值
//	Time _t = 1;
//};
//


//int main()
//{
//	
//	Date d(2024);
//	d.Print();
//
//
//	return 0;
//}



/////////////////////////////////  重要面试题

//class A
//{
//	
//public :
//	A(int a)
//		: _a1(a)
//		, _a2(_a1)
//	{}
//	void Print() {
//		cout << _a1 << " " << _a2 << endl;
//	}
//private:
//	int _a2 = 2;
//	int _a1 = 2;
//};
//int main()
//{
//	A aa(1);
//	aa.Print();
//}


// 首先这道题用到了初始化列表 , 初始化列表的初始化顺序是看声明的顺序
// 1. 先声明 _a2所以先出初始化  _a2
// 2. _a2 是用 _a1 初始化的 所以 _a2 是随机值
// 3. 接着初始化 _a1 
// 4. _a1 传参 - > 1 所以 _a1 = 1
// 所以最终输出 1 , 随机值



////////// 隐式类型转换 

// C++ 中支持内置类型转换为类的类型 , 但要有该内置类型为参数的构造函数


//class A 
//{
//public:
//	A(int aa)
//		:_a1(aa)
//		,_a2(1)
//	{
//		cout << "A(int aa)" << endl;
//	}
//
//	void Print()
//	{
//		cout << _a1 << " " << _a2 << endl;
//	}
//
//
//	A(int aa1 , int aa2)
//		:_a1(aa1)
//		,_a2(aa2)
//	{
//		cout << "A(int aa1 , int aa2)" << endl;
//	}
//
//private:
//	int _a1;
//	int _a2;
//};
//
//int main()
//{
//	//这里涉及隐式类型转换
//	// 1 产生临时对象 , 临时对象拷贝给 aa ,最终会转化为 类的类型
//	A aa = 1;
//	aa.Print();
//	
//	// C++ 11 后支持多参数转化
//	A aa2 = { 1 , 2 };
//	aa2.Print();
//	return 0;
//}



//////////// static 成员 
// 对类成员 + static 的称为 : 静态成员  -> 必须要在类外面初始化 - > 为所有类对象共享
// 对类函数 + static 的称为 : 静态成员函数
// static 修饰的成员是存在 静态区的 , 不存在对象中
// static 修饰的成员函数是没有隐含的 this 指针的  , 所以不能访问非静态 , 静态成员函数可以访问其它静态成员

// 注意: 静态成员变量不能在声明时给缺省值 , 因为这个是给初始化列表用的 , 而静态成员变量存在静态区 , 不走初始化列表


//class A 
//{
//public:
//
//	A()
//	{
//		++_a;
//	}
//	~A()
//	{
//		--_a;
//	}
//
//	static int GetCount()
//	{
//		return ++_a;
//	}
//
//private:
//	static int _a;
//};
//
////静态成员函数初始化要在全局
//int A::_a = 1;
//
//int main()
//{
//	//因为 _a 是私有的 ,想要访问可以用 Get函数
//	// 但是 成员是静态成员 ,只能定义静态成员函数
//	cout << A::GetCount();
//	return 0;
//}



////////////// 友元

// 友元函数 和 友元类

// 当想要访问另一个类中的私有时 , 可以用友元
//友元函数就是在一个类中声明 , 我是你的友元 , 这样在类外面就可以访问该类的私有内容了
// 友元只是在类中的一个声明 

// 1. 友元函数 - > 在该函数前加一个 friend 即可 , 可以放在该类的任意位置
// 2. 友元类 - > 在一个类中声明是该类的朋友就可以使用该私有


//class B;
//class A
//{
//	friend int Func(A& d);
//	friend class B;
//public:
//	void Print()
//	{
//		cout << _a << endl;
//	}
//
//	A()
//		:_a(1)
//	{}
//private:
//	int _a;
//};
//
//
//
//
//class B
//{
//public:
//
//	//要访问 A 类中的私有 
//	void func1(const A& aa)
//	{
//		cout << "A::_a : " << aa._a << endl;
//	}
//
//private:
//	int _aa;
//};
//
//
//
//// 这里写一个对 _a ++ 的函数 , 访问 A 类中的私有成员
//int Func(A& d)
//{
//	//若没有友元,这样不能访问类的私有
//	//++d._a;//err
//	return ++d._a;
//}
//
//int main()
//{
//	A d;
//	d.Print();
//	cout << Func(d) << endl;
//	B d2;
//	d2.func1(d);
//
//	return 0;
//}


////////////////////////// 内部类

// 一个类在另一个类的内部 ,这个类叫做内部类
//定义在这个类内部默认是和这个类友元


//class A
//{
//public:
//
//	class B
//	{
//		public:
//
//		//要访问 A 类中的私有 
//		void func1(const A& aa)
//		{
//			cout << "A::_a : " << aa._a << endl;
//		}
//
//	private:
//		int _aa;
//	};
//
//
//	void Print()
//	{
//		cout << _a << endl;
//	}
//
//	A()
//		:_a(1)
//	{}
//private:
//	int _a;
//};
//
//
//int main()
//{
//	A a;
//	A::B b;
//	b.func1(a);
//
//	return 0;
//}




///////////// 匿名对象

//用类型定义出来的对象是 : 匿名对象

class A
{
	
public:
	void Print()
	{
		cout << _a << endl;
	}

	A()
		:_a(1)
	{}
private:
	int _a;
};

int main()
{

	//有名对象
	A a1;
	a1.Print();

	// 匿名对象 - > 直接用类型定义
	A().Print();
	
	return 0;
}